home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 109 / EnigmaAmiga109CD.iso / dalla rivista / amiga.free / sorgenti vari / wolf3dmacsource.sit / Wolf3DMacSource / EnThink.c < prev    next >
C/C++ Source or Header  |  1994-09-20  |  13KB  |  547 lines

  1. #include "wolfdef.h"
  2.  
  3. /**********************************
  4.  
  5.     Drops a bonus item at the x,y of the actor
  6.     If there are no free item spots, nothing is done.
  7.  
  8. **********************************/
  9.  
  10. void PlaceItemType(Word shape,actor_t *ActorPtr)
  11. {
  12.     Word tile;
  13.     Word x,y;
  14.     static_t *StaticPtr;
  15.  
  16.     if (numstatics>=MAXSTATICS) {    /* Already full? */
  17.         return;                        /* Get out! */
  18.     }
  19.     StaticPtr = &statics[numstatics];    /* Get pointer to the record */
  20.  
  21. /* drop bonus items on closest tile, rather than goal tile (unless it is a closing door) */
  22.  
  23.     x = ActorPtr->x >> FRACBITS;
  24.     y = ActorPtr->y >> FRACBITS;
  25.     tile = tilemap[y][x];
  26.     if ( (tile&TI_BLOCKMOVE) && !(tile &TI_ACTOR) ) {
  27.         x = ActorPtr->goalx;
  28.         y = ActorPtr->goaly;
  29.     }
  30.     StaticPtr->pic = shape;
  31.     StaticPtr->x = (x<<FRACBITS)|0x80;
  32.     StaticPtr->y = (y<<FRACBITS)|0x80;
  33.     StaticPtr->areanumber = ActorPtr->areanumber;
  34.     tilemap[y][x] |= TI_GETABLE;        /* Mark as getable */
  35.     ++numstatics;        /* A new static */
  36. }
  37.  
  38. /**********************************
  39.  
  40.     Kill an actor
  41.     Also drop off any items you can get from a dead guy.
  42.     
  43. **********************************/
  44.  
  45. void KillActor(actor_t *ActorPtr)
  46. {
  47.     Word x,y;
  48.     
  49.     GivePoints(classinfo[ActorPtr->class].points);    /* Award the score */
  50.     switch(ActorPtr->class) {    /* Drop anything special? */
  51.     case CL_SS:
  52.         PlaceItemType(S_MACHINEGUN,ActorPtr);    /* Give a gun */
  53.         break;    
  54.     case CL_OFFICER:
  55.     case CL_MUTANT:
  56.     case CL_GUARD:
  57.         PlaceItemType(S_AMMO,ActorPtr);    /* Drop some ammo */
  58.         break;
  59.     case CL_HANS:
  60.     case CL_SCHABBS:
  61.     case CL_TRANS:
  62.     case CL_UBER:
  63.     case CL_DKNIGHT:
  64.         PlaceItemType(S_G_KEY,ActorPtr);    /* Drop a key */
  65.         break;
  66.     }
  67.     ++gamestate.killcount;        /* I killed someone! */
  68.     ActorPtr->flags = FL_DEAD;    /* remove old actor marker*/
  69.     tilemap[ActorPtr->goaly][ActorPtr->goalx] &= ~TI_ACTOR;
  70.     x = ActorPtr->x >> FRACBITS;
  71.     y = ActorPtr->y >> FRACBITS;
  72.     tilemap[y][x] |= TI_BODY;    /* body flag on most apparant, no matter what */
  73.     NewState(ActorPtr,classinfo[ActorPtr->class].deathstate);    /* start the death animation */    
  74. }
  75.  
  76. /**********************************
  77.  
  78.     Does damage points to enemy actor, either putting it into a stun frame or
  79.     killing it.
  80.     Called when an enemy is hit.
  81.     
  82. **********************************/
  83.  
  84. static Word PainTick;
  85. void DamageActor(Word damage,actor_t *ActorPtr)
  86. {
  87.     stateindex_t pain;
  88.     
  89.     madenoise = TRUE;    /* You made some noise! */
  90.  
  91. /* do double damage if shooting a non attack mode actor*/
  92.  
  93.     if ( !(ActorPtr->flags & FL_ACTIVE) ) {
  94.         if (difficulty<3) {        /* Death incarnate? */
  95.             damage <<= 1;
  96.         }
  97.         FirstSighting(ActorPtr);            /* Put into combat mode*/
  98.     }
  99.  
  100.     if (damage >= ActorPtr->hitpoints) {    /* Did I kill it? */
  101.         KillActor(ActorPtr);                /* Die!! */
  102.         return;
  103.     }
  104.     
  105.     ActorPtr->hitpoints -= damage;        /* Remove the damage */
  106.     if (ActorPtr->class == CL_MECHAHITLER && ActorPtr->hitpoints <= 250 && ActorPtr->hitpoints+damage > 250) {
  107.     /* hitler losing armor */
  108.         PlaySound(SND_SHIT);    /* Remove armor */
  109.         pain = ST_MHITLER_DIE1;
  110.     } else {
  111.         if ((ReadTick() - PainTick) >= 30) {
  112.             PainTick = ReadTick();
  113.             PlaySound(SND_PAIN);        /* Ow!! */
  114.         }
  115.         pain = classinfo[ActorPtr->class].painstate;    /* Do pain */
  116.     }
  117.     if (pain) {    /* some classes don't have pain frames */        
  118.         if (ActorPtr->state != pain) {    /* Already in pain? */
  119.             NewState(ActorPtr,pain);
  120.         }
  121.     }
  122. }
  123.  
  124. /**********************************
  125.  
  126.     Throw a Missile at the player
  127.         
  128. **********************************/
  129.  
  130. void A_Throw(actor_t *ActorPtr)
  131. {
  132.     Word angle;
  133.     int    speed;
  134.     missile_t *MissilePtr;
  135.     
  136.     PlaySound(SND_ROCKET|0x8000);
  137.     MissilePtr = GetNewMissile();        /* Create a missile */
  138.     MissilePtr->x = ActorPtr->x;
  139.     MissilePtr->y = ActorPtr->y;
  140.     MissilePtr->areanumber = ActorPtr->areanumber;
  141.  
  142.     /* get direction from enemy to player */
  143.     angle = PointToAngle(ActorPtr->x,ActorPtr->y);
  144.     angle >>= SHORTTOANGLESHIFT;
  145.     speed = costable[angle];
  146.     speed = speed/5;
  147.     MissilePtr->xspeed = -speed;
  148.     speed = sintable[angle];
  149.     speed = speed/5;
  150.     MissilePtr->yspeed = speed;
  151.     MissilePtr->pic = S_NEEDLE;        /* Hurl a needle */
  152.     MissilePtr->flags = MF_HITPLAYER | MF_HITSTATICS;    /* Can hit the player */
  153.     MissilePtr->type = MI_NEEDLE;    /* Needle missile */
  154. }
  155.  
  156. /**********************************
  157.  
  158.     Launch a rocket at the player
  159.         
  160. **********************************/
  161.  
  162. void A_Launch(actor_t *ActorPtr)
  163. {
  164.     Word angle;
  165.     int    speed;
  166.     missile_t *MissilePtr;
  167.     
  168.     PlaySound(SND_ROCKET|0x8000);
  169.     MissilePtr = GetNewMissile();
  170.     MissilePtr->x = ActorPtr->x;
  171.     MissilePtr->y = ActorPtr->y;
  172.     MissilePtr->areanumber = ActorPtr->areanumber;
  173.  
  174.     /* get direction from player to boss*/
  175.     angle = PointToAngle (ActorPtr->x,ActorPtr->y);
  176.     angle >>= SHORTTOANGLESHIFT;
  177.     speed = costable[angle];
  178.     speed = speed/5;
  179.     MissilePtr->xspeed = -speed;
  180.     speed = sintable[angle];
  181.     speed = speed/5;
  182.     MissilePtr->yspeed = speed;
  183.     MissilePtr->pic = S_ENMISSILE;    /* Rocket */
  184.     MissilePtr->flags = MF_HITPLAYER | MF_HITSTATICS;
  185.     MissilePtr->type = MI_EMISSILE;
  186.     A_Shoot(ActorPtr);    /* also shoot a bullet */
  187. }
  188.  
  189. /**********************************
  190.  
  191.     Scream a death sound
  192.         
  193. **********************************/
  194.  
  195. void A_Scream(actor_t *ActorPtr)
  196. {
  197.     Word Sound,i;
  198.     
  199.     Sound = classinfo[ActorPtr->class].deathsound;    /* Get the sound # */
  200.     if (Sound==SND_EDIE) {        /* Normal death sound? */
  201.         if (w_rnd()&1) {        /* Play one randomly */
  202.             ++Sound;
  203.         }
  204.         i = 0;
  205.         do {
  206.             StopSound(NaziSound[i]);    /* Kill all Nazi voices */
  207.         } while (++i<4);
  208.     }
  209.     PlaySound(Sound);        /* Play the sound */
  210. }
  211.  
  212. /**********************************
  213.  
  214.     Body hitting the ground
  215.         
  216. **********************************/
  217.  
  218. void A_Thud(actor_t *ActorPtr)
  219. {
  220.     PlaySound(SND_BODYFALL);
  221. }
  222.  
  223. /**********************************
  224.  
  225.     You win the game!
  226.         
  227. **********************************/
  228.  
  229. void A_Victory(actor_t *ActorPtr)
  230. {
  231.     playstate = EX_COMPLETED;
  232. }
  233.  
  234. /**********************************
  235.  
  236.     Drop Hitler's armor and let hitler run around
  237.         
  238. **********************************/
  239.  
  240. void A_HitlerMorph(actor_t *ActorPtr)
  241. {
  242.     missile_t *MissilePtr;
  243.     
  244. /* Use an inert missile for the armor remnants */
  245.  
  246.     MissilePtr = GetNewMissile();
  247.     MissilePtr->x = ActorPtr->x;    /* Pass the armor x,y */
  248.     MissilePtr->y = ActorPtr->y;
  249.     MissilePtr->areanumber = ActorPtr->areanumber;
  250.     MissilePtr->xspeed = 0;    /* No motion */
  251.     MissilePtr->yspeed = 0;
  252.     MissilePtr->flags = 0;
  253.     MissilePtr->type = -1;            /* Maximum time */
  254.     MissilePtr->pic = S_MHITLER_DIE4;    /* Set the picture */
  255.     ActorPtr->class = CL_HITLER;    /* Convert to true hitler */
  256.     ActorPtr->speed = 40/4;        /* faster without armor*/
  257. }
  258.  
  259. /**********************************
  260.  
  261.     Try to damage the player, based on skill level and player's speed
  262.         
  263. **********************************/
  264.  
  265. void A_Shoot(actor_t *ActorPtr)
  266. {
  267.     Word damage;        /* Damage to inflict */
  268.     Word distance;
  269.     
  270.     if (!areabyplayer[MapPtr->areasoundnum[ActorPtr->areanumber]]) {    /* In the same area? */
  271.         return;
  272.     }
  273.  
  274.     madenoise = TRUE;    /* I made a sound! */
  275.     if (ActorPtr->class >= CL_HANS) {        /* Boss? */
  276.         PlaySound(SND_BIGGUN|0x8000);    /* Boom! */
  277.     } else {
  278.         PlaySound(SND_GUNSHT|0x8000);    /* Bang! */
  279.     }
  280.     
  281.     if (!CheckLine(ActorPtr)) {    /* Player is behind a wall*/
  282.         return;            /* Can't shoot! */
  283.     }
  284.     distance = CalcDistance(ActorPtr);    /* How far? (0-4095 range) */
  285.  
  286.     if (distance >= TILEGLOBAL*16) {    /* Too far away? */
  287.         return;
  288.     }
  289.  
  290.     if (ActorPtr->class == CL_OFFICER || ActorPtr->class >= CL_HANS) {    /* better shots */
  291.         if (distance < (16*16)) {
  292.             distance = 0;        /* Zap the distance */
  293.         } else {
  294.             distance -= (16*16);
  295.         }
  296.     }
  297.  
  298.     if (playermoving) {    /* harder to hit when moving*/
  299.         if (distance >= (224*16)) {
  300.             return;
  301.         }
  302.         distance += (32*16);
  303.     }
  304.  
  305. /* see if the shot was a hit*/
  306.  
  307.     if ((w_rnd()*16)>distance) {
  308.         switch(difficulty) {
  309.         case 0:
  310.             damage = (w_rnd()&3)+1;
  311.             break;
  312.         case 1:
  313.             damage = (w_rnd()&7)+1;
  314.             break;
  315.         default:
  316.             damage = (w_rnd()&7)+3;
  317.         }
  318.         if (distance<(32*16)) {
  319.             damage <<= 2;
  320.         } else if (distance<(64*16)) {
  321.             damage <<= 1;
  322.         }
  323.         TakeDamage(damage,ActorPtr->x,ActorPtr->y);    /* Hit the player (Pass the killer's x,y) */
  324.     }
  325. }
  326.  
  327. /**********************************
  328.  
  329.     Bite the player
  330.         
  331. **********************************/
  332.  
  333. void A_Bite(actor_t *ActorPtr)
  334. {
  335.     Word dmg;
  336.     
  337.     PlaySound(SND_DOGBARK);    /* Take a bite! */
  338.     if (CalcDistance(ActorPtr)<=BITERANGE) {    /* In range? */
  339.         switch (difficulty) {
  340.         case 0:
  341.             dmg = (w_rnd()&3)+3;    /* Small bite */
  342.             break;
  343.         case 1:
  344.             dmg = (w_rnd()&7)+3;    /* Medium bite */
  345.             break;
  346.         default:
  347.             dmg = (w_rnd()&15)+4;    /* BIG bite */
  348.         }
  349.         TakeDamage(dmg,ActorPtr->x,ActorPtr->y);    /* Pass along the damage */
  350.     }
  351. }
  352.  
  353. /**********************************
  354.  
  355.     Return the distance between the player and this actor
  356.         
  357. **********************************/
  358.  
  359. Word CalcDistance(actor_t *ActorPtr)
  360. {
  361.     Word absdx;
  362.     Word absdy;
  363.     
  364.     absdx = w_abs(ActorPtr->x - actors[0].x);
  365.     absdy = w_abs(ActorPtr->y - actors[0].y);
  366.     return (absdx > absdy) ? absdx : absdy;    /* Return the larger */
  367. }
  368.  
  369. /**********************************
  370.  
  371.     Called every few frames to check for sighting and attacking the player
  372.         
  373. **********************************/
  374.  
  375. Word shootchance[8] = {256,64,32,24,20,16,12,8};
  376.  
  377. void A_Target(actor_t *ActorPtr)
  378. {
  379.     Word chance;    /* % chance of hit */
  380.     Word distance;    /* Distance of critters */
  381.     
  382.     if (!areabyplayer[MapPtr->areasoundnum[ActorPtr->areanumber]] || !CheckLine(ActorPtr)) {
  383.         ActorPtr->flags &= ~FL_SEEPLAYER;    /* Can't see you */
  384.         return;
  385.     }
  386.     
  387.     ActorPtr->flags |= FL_SEEPLAYER;        /* I see you */
  388.     distance = CalcDistance(ActorPtr);        /* Get the distance */
  389.     
  390.     if (distance < BITERANGE) {    /* always attack when this close */
  391.         goto attack;
  392.     }
  393.  
  394.     if (ActorPtr->class == CL_DOG) {    /* Dogs can only bite */
  395.         return;
  396.     }
  397.         
  398.     if (ActorPtr->class == CL_SCHABBS && distance <= TILEGLOBAL*4) {    
  399.         goto attack;        /* Dr. schabbs always attacks */
  400.     }
  401.  
  402.     if (distance >= TILEGLOBAL*8) {        /* Too far? */
  403.         return;
  404.     }
  405.             
  406.     chance = shootchance[distance>>FRACBITS];    /* Get the base chance */
  407.     if (difficulty >= 2) {
  408.         chance <<= 1;        /* Increase chance */
  409.     }
  410.     if (w_rnd() < chance) {
  411. attack:        /* go into attack frame*/
  412.         NewState(ActorPtr,classinfo[ActorPtr->class].attackstate);
  413.     }
  414. }
  415.  
  416. /**********************************
  417.  
  418.     MechaHitler takes a step
  419.         
  420. **********************************/
  421.  
  422. void A_MechStep(actor_t *ActorPtr)
  423. {
  424.     PlaySound(SND_MECHSTEP|0x8000);    /* Step sound */
  425.     A_Target(ActorPtr);    /* Shoot player */
  426. }
  427.  
  428. /**********************************
  429.  
  430.     Chase the player
  431.         
  432. **********************************/
  433.  
  434. void T_Chase(actor_t *ActorPtr)
  435. {
  436.     Word move;
  437.     
  438. /* if still centered in a tile, try to find a move */
  439.  
  440.     if (ActorPtr->flags & FL_NOTMOVING) {
  441.         if (ActorPtr->flags & FL_WAITDOOR) {
  442.             TryWalk(ActorPtr);        /* Waiting for a door to open*/
  443.         } else if (ActorPtr->flags & FL_SEEPLAYER) {
  444.             SelectDodgeDir(ActorPtr);    /* Dodge the player's bullets */
  445.         } else {
  446.             SelectChaseDir(ActorPtr);    /* Directly chase the player */
  447.         }
  448.         if (ActorPtr->flags & FL_NOTMOVING) {
  449.             return;            /* Still blocked in */
  450.         }
  451.     }
  452.  
  453. /* OPTIMIZE: integral steps / tile movement */
  454.  
  455. /* cover some distance*/
  456.  
  457.     move = ActorPtr->speed*TicCount;        /* this could be put in the class info array*/
  458.  
  459.     while (move) {
  460.         if (move < ActorPtr->distance) {
  461.             MoveActor(ActorPtr,move);    /* Move one step */
  462.             return;
  463.         }
  464.     
  465.         /* reached goal tile, so select another one*/
  466.         
  467.         move -= ActorPtr->distance;
  468.         MoveActor(ActorPtr,ActorPtr->distance);        /* move the last 1 to center*/
  469.  
  470.         if (ActorPtr->flags & FL_SEEPLAYER) {
  471.             SelectDodgeDir(ActorPtr);    /* Dodge the player */
  472.         } else {
  473.             SelectChaseDir(ActorPtr);    /* Directly chase the player */
  474.         }
  475.         if (ActorPtr->flags & FL_NOTMOVING) {
  476.             return;                        /* object is blocked in*/
  477.         }
  478.     }
  479. }
  480.  
  481. /**********************************
  482.  
  483.     Move all actors for a single frame
  484.     Actions are performed as the state is entered
  485.         
  486. **********************************/
  487.  
  488. typedef void (*call_t)(actor_t *ActorPtr);
  489.  
  490. static void A_Nothing(actor_t *ActorPtr) {}
  491.  
  492. call_t thinkcalls[] = {
  493.     A_Nothing,    /* No action */
  494.     T_Stand,    /* Stand at attention */
  495.     T_Chase        /* Chase the player */
  496. };
  497.  
  498.  
  499. call_t actioncalls[] = {
  500.     A_Nothing,
  501.     A_Target,
  502.     A_Shoot,
  503.     A_Bite,
  504.     A_Throw,
  505.     A_Launch,
  506.     A_HitlerMorph,
  507.     A_MechStep,
  508.     A_Victory,
  509.     A_Scream,
  510.     A_Thud
  511. };
  512.  
  513. void MoveActors(void)
  514. {
  515.     Word i;        /* Index */
  516.     state_t *StatePtr;    /* Pointer to state logic */
  517.     actor_t *ActorPtr;    /* Pointer to Actor code */
  518.     
  519.     if (numactors<2) {    /* No actors to check? */
  520.         return;
  521.     }
  522.     i = 1;                    /* Init index */
  523.     ActorPtr = &actors[1];    /* Init the pointer to the actors */
  524.     do {
  525.         if (!(ActorPtr->flags&FL_ACTIVE)    /* Is this actor in view? */
  526.         && !areabyplayer[MapPtr->areasoundnum[ActorPtr->areanumber]]) {
  527.             goto Skip;
  528.         }
  529.  
  530.         StatePtr = &states[ActorPtr->state];    /* Get the current state */
  531.         if (ActorPtr->ticcount>TicCount) {    /* Count down the time */
  532.             ActorPtr->ticcount-=TicCount;
  533.         } else {        /* change state if time's up */
  534.             ActorPtr->state = StatePtr->next;    /* Set the next state */
  535.             StatePtr = &states[ActorPtr->state];    /* Get the new state ptr */
  536.             ActorPtr->ticcount = StatePtr->tictime;    /* Reset the time */
  537.             ActorPtr->pic = StatePtr->shapenum;        /* Set the new picture # */
  538.             /* action think */            
  539.             actioncalls[StatePtr->action](ActorPtr);    /* Call the code */
  540.         }
  541.         thinkcalls[StatePtr->think](ActorPtr);    /* Perform the action */
  542. Skip:    /* Next entry */
  543.         ++ActorPtr;
  544.     } while (++i<numactors);
  545. }
  546.  
  547.